﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace UML_editor_Class_Diagam_v1._0
{
    /// <summary>
    /// Структура для хранения основных параметров объекта диаграммы "класс"
    /// </summary>
    public struct class_element
    {
        public string name;             //имя класса
        public List<string> properties; //перечень свойств класса
        public List<string> metods;      //перечень методов класса

    };
    public partial class class_diagram_element : UserControl
    {
        private int x_prop;// глобальные координаты, показывающие нахождение самого нижнего свойства
        private int y_prop;
        private int x_met;// глобальные координаты, показывающие нахождение самого нижнего метода
        private int y_met;

        public delegate void ClassChangedEventHandler(object sender, ClassArgs e);
        public event ClassChangedEventHandler ClassChanged;
      
        public class_diagram_element()
        {

            InitializeComponent();
            label1_name.Click += label_Click;
            this.Click += class_diagram_element_Click;
            Initialize();

            this.Paint += new System.Windows.Forms.PaintEventHandler(this.class_diagram_element_Paint);
        }
        public class ClassArgs : EventArgs
        {
            public string name_class;
        }
        /// <summary>
        /// Функция перерисовки линий, отделяющих имя класса от свойств 
        /// и свойства класса от методов
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void class_diagram_element_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Graphics g = this.CreateGraphics();
            Pen p = new Pen(Color.Black, 2);
            int y_l = y_prop + 13 + 12;
            if (y_prop == 30)
                y_l = 39;
            g.Clear(Color.White);
            g.DrawLine(p, 0, 35, this.Size.Width, 35);      //линия,отделяющая имя класса от свойств
            g.DrawLine(p, 0, y_l, this.Size.Width, y_l);    //линия,отделяющая свойства от методов
            g.Dispose();
        }

        /// <summary>
        /// Добавление нового свойства
        /// </summary>
        public void add_properties()
        {
            //вставляем в конец лэйбл
            y_met += 13 + 13;
            x_met = 15;
            add_Label(x_met, y_met, "Input properties");

            //обозначаем последнее свойство
            y_prop += 13 + 13;
            x_prop = 15;

            //смещение всех текстовых полей на 1 вниз, начиная от места вставки свойства
            string str = "Input properties";
            string cur = "";
            foreach (Control cnt in this.Controls)
            {
                if (cnt.Location.Y >= y_prop)
                {
                    cur = cnt.Text;
                    cnt.Text = str;
                    str = cur;
                }
            }

        }

        /// <summary>
        /// Начальная инициализация необходимых данных
        /// </summary>
        private void Initialize()
        {
            x_prop = 15;
            y_prop = 30;
            x_met = 15;
            y_met = 30;

        }

        /// <summary>
        /// Задание класса по имеющимся параметрам
        /// </summary>
        /// <param name="cl"></param>
        public void load_class(class_element cl)
        {
            //установка имени класса
            label1_name.Text = cl.name;
            Initialize();

            //установка свойств
            for (int i = 0; i < cl.properties.Count; i++)
            {
                y_prop += 13 + 13;
                y_met += 13 + 13;
                add_Label(x_prop, y_prop, cl.properties[i]);
               
            }

            //установка методов
            for (int i = 0; i < cl.metods.Count; i++)
            {
                y_met += 13 + 13;
                add_Label(x_met, y_met, cl.metods[i]);
                
            }


        }

        /// <summary>
        /// Добавление метода класса
        /// </summary>
        public void add_method()
        {
            //добавляем в конец новый лабел
            y_met += 13 + 13;
            x_met = 15;
            add_Label(x_met, y_met, "Input method");


        }

        /// <summary>
        /// Считывание информации о классе в структуру class_element
        /// </summary>
        /// <returns></returns>
        public class_element return_class()
        {
            class_element my_class = new class_element();
            List<string> prop = new List<string>();
            List<string> met = new List<string>();

            //проходим по всем контролам
            foreach (Control cnt in this.Controls)
            {
                if (cnt.Location.Y == label1_name.Location.Y)
                    my_class.name = cnt.Text;

                 //если контрол находится выше координаты последнего свойства,то записываем в свойства
                else if (cnt.Location.Y <= y_prop)
                    prop.Add(cnt.Text);

                 //если контрол находится ниже координаты последнего свойства,то записываем в методы
                else
                    met.Add(cnt.Text);
            }
            my_class.properties = prop;
            my_class.metods = met;

            return my_class;
        }

        /// <summary>
        /// Редактирование свойств, методов, имени
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void label_Click(object sender, EventArgs e)
        {
            Label l = sender as Label;

            //определяем местоположение лабел
            Point p = (Point)l.Location;
            TextBox tb = new TextBox();
            tb.Text = l.Text;

            //заменяем лабел на текстбокс, чтобы была возможность редактирования
            this.Controls.Remove(l);
            this.Controls.Add(tb);
            tb.Location = p;
            tb.KeyDown += textBox_KeyDown;

            //если при этом на поле остались текстбоксы, то необходимо их перевести в лабел
            string text = "";
            foreach (Control cnt in this.Controls)
            {
                if ((cnt.GetType() == typeof(TextBox)) && (cnt.Location != p))
                {

                    Point p1 = (Point)cnt.Location;
                    if (cnt.Text.Length > 0)
                    {
                        text = cnt.Text;

                    }
                    this.Controls.Remove(cnt);
                    add_Label(p1.X, p1.Y, text);

                }
            }


        }
        /// <summary>
        /// Редактирование и удаление свойств и методов
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            TextBox tb = sender as TextBox;
            string text = "";
            Point p = (Point)tb.Location;

            //если нажата клавиша Enter
            //то считаем редактирвоание завершенным
            if (e.KeyCode == Keys.Enter)
            {
                if (tb.Text.Length > 0)
                {
                    text = tb.Text;

                }

                //заменяем текстбокс на лабел с введенным текстом
                this.Controls.Remove(tb);
                add_Label(p.X, p.Y, text);
            }

             //если нажата клавиша Delete
            //то удаляем текущее свойство или метод
            else if (e.KeyCode == Keys.Delete)
            {
                if (p.Y > 30) //исключаем возможность удаления имени класса
                {
                    //сохраняем местоположение удаяемого объекта
                    Point tmp = new Point();
                    this.Controls.Remove(tb);
                    if (p.Y <= y_prop)
                    {
                        y_prop -= 13 + 13;
                        y_met -= 13 + 13;
                    }
                    else
                        y_met -= 13 + 13;


                    //поднимаем вверх все нижележащие контролы
                    foreach (Control cnt in this.Controls)
                    {
                        if (cnt.Location.Y > p.Y)
                        {
                            tmp = cnt.Location;
                            cnt.Location = p;
                            p = tmp;

                        }
                    }
                }

            }

        }

        // <summary>
        /// Добавление элемента Label в заданные координаты с заданным текстом
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="text"></param>
        private void add_Label(int x, int y, string text)
        {
            Label l = new Label();
            this.Controls.Add(l);
            l.Location = new Point(x, y);
            l.BackColor = Color.Transparent;
            l.Text = text;
            l.Click += label_Click;

        }

        /// <summary>
        /// Прекращение редактирования элементов при клике на поле класса
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void class_diagram_element_Click(object sender, EventArgs e)
        {
            //если мы не в режиме отстройки связей,то просто закрываем все текстбоксы
            if (Form1.isLinkAction == false)
            {
                string text = "";

                //проходим по всем контролам
                foreach (Control cnt in this.Controls)
                {
                    //если контрол является текстбокосм, то замняем его на лабел
                    if (cnt.GetType() == typeof(TextBox))
                    {

                        Point p = (Point)cnt.Location;
                        if (cnt.Text.Length > 0)
                        {
                            text = cnt.Text;

                        }
                        this.Controls.Remove(cnt);
                        add_Label(p.X, p.Y, text);

                    }
                }
            }
            //иначе при одинарном щелчке левой кнопки мыши мы посылаем сигнал общему классу о том
            //что необходимо считать координаты для связей (только там мы можем определить sender'а среди контролов) 
            else
            {
                ClassArgs args = new ClassArgs();
                args.name_class=label1_name.Text;
                OnClassChanged(args);
            }
        }
        protected void OnClassChanged(ClassArgs e)
        {
            ClassChanged(this, e);
        }  
        
        
    }
}
